package org.wheelmap.android.tango.mode.math;
import com.vividsolutions.jts.algorithm.ConvexHull;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Polygon;
import org.rajawali3d.math.vector.Vector2;
import java.util.List;
/**
* @author julien Gaffuri
* (modified) https://sourceforge.net/p/opencarto/code/HEAD/tree/trunk/server/src/main/java/org/opencarto/algo/base/SmallestSurroundingRectangle.java
*/
public class SmallestSurroundingRectangle {
public static Polygon get(List<Vector2> points) {
GeometryFactory geometryFactory = new GeometryFactory();
Coordinate[] coordinates = new Coordinate[points.size() + 1];
for (int i = 0; i < points.size(); i++) {
Vector2 v = points.get(i);
coordinates[i] = new Coordinate(v.getX(), v.getY(), 0);
}
// close polygon
coordinates[coordinates.length - 1] = coordinates[0];
return get(geometryFactory.createPolygon(coordinates));
}
public static Polygon get(Geometry geom) {
return get(geom, geom.getFactory());
}
public static Polygon get(Geometry geom, GeometryFactory gf) {
Geometry hull_ = (new ConvexHull(geom)).getConvexHull();
if (!(hull_ instanceof Polygon)) return null;
Polygon convHull = (Polygon) hull_;
Coordinate c = geom.getCentroid().getCoordinate();
Coordinate[] coords = convHull.getExteriorRing().getCoordinates();
double minArea = Double.MAX_VALUE, minAngle = 0.0;
Polygon ssr = null;
Coordinate ci = coords[0], cii;
for (int i = 0; i < coords.length - 1; i++) {
cii = coords[i + 1];
double angle = Math.atan2(cii.y - ci.y, cii.x - ci.x);
Polygon rect = (Polygon) Rotation.get(convHull, c, -1.0 * angle, gf).getEnvelope();
double area = rect.getArea();
if (area < minArea) {
minArea = area;
ssr = rect;
minAngle = angle;
}
ci = cii;
}
return Rotation.get(ssr, c, minAngle, gf);
}
public static Polygon get(Geometry geom, boolean preserveSize) {
return get(geom, geom.getFactory(), preserveSize);
}
public static Polygon get(Geometry geom, GeometryFactory gf, boolean preserveSize) {
if (!preserveSize) return get(geom, gf);
Polygon out = get(geom, gf);
double ini = geom.getArea();
double fin = out.getArea();
if (fin == 0) {
return out;
}
return Scaling.get(out, out.getCentroid().getCoordinate(), Math.sqrt(ini / fin), gf);
}
}